package org.example.task.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Redis操作工具类 - 通用增强版
 */
@Component
public class RedisUtil {

    private final RedisTemplate<String, Object> redisTemplate;

    @Autowired
    public RedisUtil(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    // ============================== 通用操作 ==============================

    /**
     * 设置缓存
     * @param key 键
     * @param value 值
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置带过期时间的缓存
     * @param key 键
     * @param value 值
     * @param timeout 过期时间
     * @param unit 时间单位
     */
    public void setEx(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 设置带过期时间的缓存（秒）
     * @param key 键
     * @param value 值
     * @param timeout 过期时间（秒）
     */
    public void setExSeconds(String key, Object value, long timeout) {
        setEx(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取缓存
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 获取缓存并转换为指定类型
     * @param key 键
     * @param clazz 目标类型
     * @return 值
     * @param <T> 泛型类型
     */
    public <T> T get(String key, Class<T> clazz) {
        Object value = get(key);
        return value != null ? clazz.cast(value) : null;
    }

    // ============================== 删除操作 ==============================

    /**
     * 删除单个key
     * @param key 键
     * @return 是否成功
     */
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 批量删除key
     * @param keys 键集合
     * @return 删除的数量
     */
    public Long delete(Collection<String> keys) {
        return redisTemplate.delete(keys);
    }

    /**
     * 批量删除匹配模式的key
     * @param pattern 匹配模式（例如："user:*"）
     * @return 删除的数量
     */
    public Long deleteByPattern(String pattern) {
        Set<String> keys = redisTemplate.keys(pattern);
        return keys != null && !keys.isEmpty() ? delete(keys) : 0L;
    }

    // ============================== 过期时间 ==============================

    /**
     * 设置key过期时间
     * @param key 键
     * @param timeout 过期时间
     * @param unit 时间单位
     * @return 是否成功
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 设置key过期时间（秒）
     * @param key 键
     * @param timeout 过期时间（秒）
     * @return 是否成功
     */
    public Boolean expireSeconds(String key, long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取key剩余生存时间
     * @param key 键
     * @param unit 时间单位
     * @return 剩余时间
     */
    public Long getExpire(String key, TimeUnit unit) {
        return redisTemplate.getExpire(key, unit);
    }

    /**
     * 获取key剩余生存时间（秒）
     * @param key 键
     * @return 剩余时间（秒）
     */
    public Long getExpireSeconds(String key) {
        return getExpire(key, TimeUnit.SECONDS);
    }

    // ============================== 存在判断 ==============================

    /**
     * 判断key是否存在
     * @param key 键
     * @return 是否存在
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    // ============================== 哈希操作 ==============================

    /**
     * 设置Hash值
     * @param key 键
     * @param hashKey 哈希键
     * @param value 值
     */
    public void hSet(String key, String hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 获取Hash值
     * @param key 键
     * @param hashKey 哈希键
     * @return 值
     */
    public Object hGet(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 获取Hash值并转换为指定类型
     * @param key 键
     * @param hashKey 哈希键
     * @param clazz 目标类型
     * @return 值
     * @param <T> 泛型类型
     */
    public <T> T hGet(String key, String hashKey, Class<T> clazz) {
        Object value = hGet(key, hashKey);
        return value != null ? clazz.cast(value) : null;
    }

    /**
     * 获取整个Hash
     * @param key 键
     * @return Map结构
     */
    public Map<Object, Object> hGetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    // ============================== 列表操作 ==============================

    /**
     * 向列表左侧添加元素
     * @param key 键
     * @param value 值
     * @return 列表长度
     */
    public Long lPush(String key, Object value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 获取列表范围
     * @param key 键
     * @param start 开始索引
     * @param end 结束索引
     * @return 值列表
     */
    public List<Object> lRange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 获取列表范围并转换为指定类型
     * @param key 键
     * @param start 开始索引
     * @param end 结束索引
     * @param clazz 目标类型
     * @return 值列表
     * @param <T> 泛型类型
     */
    public <T> List<T> lRange(String key, long start, long end, Class<T> clazz) {
        List<Object> list = lRange(key, start, end);
        return list.stream()
                .map(clazz::cast)
                .collect(Collectors.toList());
    }
}